# @Time : 2020/6/29 10:48
# @Author : Fioman 
# @Phone : 13149920693
"""
每门面向对象的语言至少都有一种获取对象的字符串表示形式的标准方式.Python提供了两种方式.
repr() 以便于开发者理解的方式返回对象的字符串表示形式.
str() 以便于用户理解的方式返回对象的字符串表示形式.
在Python3中,__repr__,__str__和__format__都必须返回Unicode字符串(str类型).只有__bytes__方法应该返回字节序列(bytes类型)
"""
from array import array
import math


class Vector2d(object):
    typcode = 'd'  # 1.typecode是类属性,在Vector2d实例和直接序列之间转换时使用.

    def __init__(self, x, y):  # 在__init__方法中把x和y转换成浮点数,尽早捕获错误,以防止调用Vector2d函数时传入不当参数
        self.x = float(x)
        self.y = float(y)

    def __iter__(self):  # 定义__iter__方法,把Vector2d实例变成可迭代对象,这样才能拆包(例如,x,y = my_vector).这个方法的实现方式很简单,
        # 直接调用生成器表达式一个接一个产出分量.
        return (i for i in (self.x, self.y))

    def __repr__(self):  # 4. __repr__方法使用{!r}获取各个分量的表示形式,然后插值,构成一个字符串;因为Vector2d实例时可迭代对象,所以*self会把x和y分量供给format函数
        class_name = type(self).__name__
        return "{}({!r},{!r})".format(class_name, *self)

    def __str__(self):  # 从可迭代的vector2d中轻松获取一个元组,显示为一个序列
        return str(tuple(self))

    def __bytes__(self):  # 为了生成字节序列,我们把typecode转换成字节序列,然后..........
        return (bytes([ord(self.typcode)]) + bytes(array(self.typcode, self)))  # 7.迭代Vector2d实例,得到一个数组,再把数组转换成字节序列.

    def __eq__(self, other):  # 为了尽快的比较所有分量,在操作数中构建元组.对Vector2d实例来说,可以这样做,不过仍然有问题.
        return tuple(self) == tuple(other)

    def __abs__(self):  # 模式x和y分量构成的直角三角形的斜边长
        return math.hypot(self.x, self.y)

    def __bool__(self):  # __bool__方法使用abs(self)计算模,然后把结构转换成bool值.因此0.0是False,非零值是True
        return bool(abs(self))

    # 我们可以把Vector3d实例转换成字节序列了;同理,也应该能从字节序列转换成Vector2d实例.
    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0]) # 从第一个字节中读取typecode
        memv = memoryview(octets[1:]).cast(typecode) # 使用传入的octets字节序列创建一个memoryview,然后使用typecode转换.
        return cls(*memv) # 拆包转换后的memoryview,得到一个构造方法所需要的一对参数.


if __name__ == '__main__':
    v1 = Vector2d(3, 4)
    print("v1.x = {},v1.y = {}".format(v1.x, v1.y))

    x, y = v1
    print("x = {},y = {}".format(x, y))

    print("v1 = {}".format(v1))

    v1_clone = eval(repr(v1))
    print("v1 == v1_clone : {}".format(v1 == v1_clone))

    print("v1 = {}".format(v1))

    octets = bytes(v1)
    print("octets = {}".format(octets))
    abs_v1 = abs(v1)
    print("abs_v1 = {}".format(abs_v1))
    print("bool_v1 = {},bool_vector2d = {}".format(bool(v1), bool(Vector2d(0, 0))))
